package wx.wechat.service.mp;

import com.alibaba.fastjson.JSONObject;
import com.aliyun.oss.common.utils.HttpUtil;
import com.ruitaowang.core.domain.BankCardBag;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import org.dom4j.DocumentException;
import org.slf4j.LoggerFactory;
import org.springframework.util.ObjectUtils;
import tech.lingyi.wx.msg.out.TemplateData;
import wx.wechat.common.Configure;
import wx.wechat.common.RandomStringGenerator;
import wx.wechat.common.signature.Signature;
import wx.wechat.service.WXService;

import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.time.Instant;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;

public class MPService extends WXService {

    protected final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(getClass());
    /**
     * @return
     * @function 获取接口调用凭据 Access_Token
     */
    public Map<String, String> fetchAccessToken4ClientCredential() throws IOException {

        //路径
        final String path = "/cgi-bin/token";

        Map<String, String> params = new HashMap<>();

        params.put("appid", Configure.appID);

        params.put("secret", Configure.appSecret);

        params.put("grant_type", "client_credential");

        //调用远程获取的函数
        Map<String, String> result = this.getWithParams(this.API_WEIXIN_HOST, path, params);

//        System.out.println(result);

        return result;
    }

    /**
     * @return
     * @function 获取用户信息 - 是否关注公共号
     */
    public Map<String, String> fetchUserinfoByAccessTokenAndOpenId(String accessToken, String openid) throws IOException {

        //路径
        final String path = "/cgi-bin/user/info";

        Map<String, String> params = new HashMap<>();

        params.put("access_token", accessToken);

        params.put("openid", openid);

        params.put("lang", "zh_CN");

        //调用远程获取的函数
        Map<String, String> result = this.getWithParams(this.API_WEIXIN_HOST, path, params);

        return result;
    }

    /**
     * @return
     * @function 从远端获取到Access Token,注意,该AccessToken用于用户认证
     */
    public Map<String, String> fetchAccessTokenByCode4Authorization(String code) throws IOException {

        //路径
        final String path = "/sns/oauth2/access_token";

        Map<String, String> params = new HashMap<>();

        params.put("appid", Configure.appID);

        params.put("secret", Configure.appSecret);

        params.put("code", code);

        params.put("grant_type", "authorization_code");

        //调用远程获取的函数
        Map<String, String> result = this.getWithParams(this.API_WEIXIN_HOST, path, params);

//        System.out.println(result);

        return result;
    }

    /**
     * 获取用户信息
     * @return
     * @function 从远端获取到Access Token,注意,该AccessToken用于用户认证
     * @url https://api.weixin.qq.com/sns/userinfo?access_token=EHtVZcvhD6x475HJ2ukUc0u3BqiMdjJ2gc9x-j2fil4i63M-aS9qHVmcHxVw19tLdalzo8VjxIJzMyuIJKIiis1h2JoZmy5wRp9IWwiHxRab3cDu-SxQHSm10h47bHyVRKYeAEALES&openid=OPENID&lang=zh_CN
     */
    public Map<String, String> fetchUserinfoByAccessToken(String accessToken, String openid) throws IOException {

        //路径
        final String path = "/sns/userinfo";

        Map<String, String> params = new HashMap<>();

        params.put("access_token", accessToken);

        params.put("openid", openid);

        params.put("lang", "zh_CN");

        params.put("grant_type", "authorization_code");

        //调用远程获取的函数
        Map<String, String> result = this.getWithParams(this.API_WEIXIN_HOST, path, params);

//        System.out.println(result);

        return result;
    }

    /**
     * @param accessToken
     * @return {
     * <p>
     * "errcode":0,
     * <p>
     * "errmsg":"ok",
     * <p>
     * "ticket":"bxLdikRXVbTPdHSM05e5u5sUoXNKd8-41ZO3MhKoyN5OfkWITDGgnr2fwJ0m9E8NYzWKVZvdVtaUgWvsdshFKA",
     * <p>
     * "expires_in":7200
     * <p>
     * }
     * @function 根据AccessToken获取JSAPI_TICKET
     * @url https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi
     */
    public Map<String, String> fetchTicketByAccessToken(String accessToken, String type) throws IOException {

        //请求路径
        final String path = "/cgi-bin/ticket/getticket";

        Map<String, String> params = new HashMap<>();

        params.put("access_token", accessToken);

        params.put("type", type);

        Map<String, String> result = this.getWithParams(this.API_WEIXIN_HOST, path, params);

//        System.out.println(result);

        return result;

    }

    /**
     * @function  获取code
     * @url https://open.weixin.qq.com/connect/oauth2/authorize?appid=xxx&redirect_uri=http://test.ruitaowang.com/test&response_type=code&scope=snsapi_base
     */
    public String fetchCodeForLoginUrl(String fromUserIdOtherID){//from | userId | otherId(个人二维码，实体店扫码支付，商品ID，文章ID，名片ID)

        //请求路径
        final String path = "/connect/oauth2/authorize";
        StringBuffer url = new StringBuffer();
        url.append("https://")
                .append(this.OPEN_API_WEIXIN_HOST)
                .append(path)
                .append("?")
                .append("appid").append("=").append(Configure.appID).append("&")
                .append("redirect_uri").append("=").append(toUrl(fromUserIdOtherID)).append("&")
                .append("response_type").append("=").append("code").append("&")
                .append("scope").append("=").append("snsapi_userinfo");
        System.out.println(url);
        return url.toString();
    }

    public String toUrl(String fromUserIdOtherID){
        return Configure.returnUri+"/"+fromUserIdOtherID;

    }

    public String fetchCodeForLoginUrlForSM(String fromUserIdOtherID){

        //请求路径
        final String path = "/connect/oauth2/authorize";
        StringBuffer url = new StringBuffer();
        url.append("https://")
                .append(this.OPEN_API_WEIXIN_HOST)
                .append(path)
                .append("?")
                .append("appid").append("=").append(Configure.appID).append("&")
                .append("redirect_uri").append("=").append( toUrl(fromUserIdOtherID)).append("&")
                .append("response_type").append("=").append("code").append("&")
                .append("scope").append("=").append("snsapi_base");
        System.out.println(url);
        return url.toString();
    }

    /**
     * weixin：//wxpay/bizpayurl?sign=XXXXX&appid=XXXXX&mch_id=XXXXX&product_id=XXXXXX&time_stamp=XXXXXX&nonce_str=XXXXX
     * @return
     * @throws IOException
     */
    public Map<String, Object> wxShareConfig(String url) throws Exception{
        Map<String, String> credential = fetchAccessToken4ClientCredential();
        String accessToken = credential.get("access_token");
        if(ObjectUtils.isEmpty(credential) || ObjectUtils.isEmpty(accessToken)){
            return null;
        }
        Map<String, String> ticketMap = fetchTicketByAccessToken(accessToken, "jsapi");
        String ticket = ticketMap.get("ticket");
        if(ObjectUtils.isEmpty(ticketMap) || ObjectUtils.isEmpty(ticket)){
            return null;
        }

        //请求路径
        Map<String, Object> requestData = new HashMap();
        requestData.put("jsapi_ticket", ticket);
        requestData.put("noncestr",  RandomStringGenerator.getRandomStringByLength(20));
        requestData.put("timestamp", Instant.now().getEpochSecond());
        requestData.put("url", url);
        requestData.put("signature", Signature.getSign4MP(requestData));
//        requestData.put("appId", Configure.appID);
        return requestData;

    }

    /**
     * 微信企业付款
     * https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers
     * @return
            {
                nonce_str=ict1kn6ar6c9df0x57sa,
                partner_trade_no=reward2,
                payment_time=2017-08-18 15:40:06,
                payment_no=1000018301201708189223134713,
                return_msg=,
                return_code=SUCCESS
            }
     * @throws IOException
     */
    public Map<String, Object> transfers(String partnerTradeNo, String openid, Integer amount, String spbillCreateIp,String apiCertPath) throws Exception{

        //请求路径
        Map<String, String> requestData = new HashMap();
        requestData.put("partner_trade_no", "new3reward"+partnerTradeNo);
        requestData.put("mch_appid", Configure.appID);
        requestData.put("mchid", Configure.mchID);
        requestData.put("nonce_str",  RandomStringGenerator.getRandomStringByLength(20));
        requestData.put("openid", openid);
        requestData.put("check_name", "NO_CHECK");//验证用户名
     //   requestData.put("re_user_name", reUserName);//接收者账户名字
        requestData.put("amount", amount+"");//转账金额
        requestData.put("desc", "收益提现");//转账描述
        requestData.put("spbill_create_ip", spbillCreateIp);//ip地址
        requestData.put("sign", Signature.getSign4MPString(requestData));

        return postByXMLForSSL("https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers", requestData, apiCertPath);
    }

    /**
     * 微信付款到银行卡
     * @param partnerTradeNo
     * @param amount
     * @param apiCertPath
     * @return
     * @throws Exception
     */
    public Map<String, Object> payToBank(String partnerTradeNo, Integer amount, String apiCertPath, BankCardBag bankCardBag) throws Exception{

        //请求路径
        Map<String, String> requestData = new HashMap();
        requestData.put("mch_id", Configure.mchID);//商户号
        requestData.put("partner_trade_no", "new3reward"+partnerTradeNo);//商户企业付款单号
        requestData.put("nonce_str",  RandomStringGenerator.getRandomStringByLength(20));//随机字符串
        requestData.put("enc_bank_no", bankCardBag.getBankId());//收款方银行卡号
        requestData.put("enc_true_name", bankCardBag.getBankUserName());//收款方用户名
        requestData.put("bank_code", bankCardBag.getBankBranch());//收款方开户行
        requestData.put("amount", amount+"");//付款金额
        requestData.put("desc", "收益提现");//付款说明
        requestData.put("sign", Signature.getSign4MPString(requestData));//签名
        return postByXMLForSSL("https://api.mch.weixin.qq.com/mmpaysptrans/pay_bank", requestData, apiCertPath);
    }


    /**
     * 微信公众平台 微信裂变红包接口
     * @param partnerTradeNo
     * @param num
     * @param amount
     * @param openid
     * @param spbillCreateIp
     * @param apiCertPath
     * @return
     * @throws Exception
     */
    public Map<String, Object> wxhongbaofl(String partnerTradeNo,String remark,String wishing,String actName,String num,String amount, String openid,String spbillCreateIp,String apiCertPath) throws Exception{

        //请求路径
        Map<String, String> requestData = new HashMap();
        requestData.put("mch_billno","hongbao"+partnerTradeNo);
        requestData.put("mch_id", Configure.mchID);//商户号
        requestData.put("wxappid", Configure.appID);//公众账号appid
        requestData.put("nonce_str",  RandomStringGenerator.getRandomStringByLength(20));
        requestData.put("re_openid", openid);
        requestData.put("act_name",actName);//活动名称
        requestData.put("send_name", "龙蛙");//商户名称
        requestData.put("amt_type", "ALL_RAND");//红包金额设置方式  ALL_RAND-随机
        requestData.put("remark", remark);//备注
        requestData.put("wishing", wishing);//红包祝福语
        requestData.put("total_num", num);//红包发放总人数
        requestData.put("total_amount", amount);//付款金额
        requestData.put("client_ip", spbillCreateIp);//IP地址
        requestData.put("sign", Signature.getSign4MPString(requestData));

        return postByXMLForSSL("https://api.mch.weixin.qq.com/mmpaymkttransfers/sendgroupredpack", requestData, apiCertPath);
    }

    /**
     * 微信公众平台 微信红包接口
     * @param partnerTradeNo
     * @param remark
     * @param wishing
     * @param actName
     * @param amount
     * @param openid
     * @param spbillCreateIp
     * @param apiCertPath
     * @return
     * @throws Exception
     */
    public Map<String, Object> wxhongbao(String partnerTradeNo,String remark,String wishing,String actName,String amount, String openid,String spbillCreateIp,String apiCertPath) throws Exception{

        //请求路径
        Map<String, String> requestData = new HashMap();
        requestData.put("mch_billno","hongbao"+partnerTradeNo);
        requestData.put("mch_id", Configure.mchID);//商户号
        requestData.put("wxappid", Configure.appID);//公众账号appid
        requestData.put("nonce_str",  RandomStringGenerator.getRandomStringByLength(20));
        requestData.put("re_openid", openid);
        requestData.put("act_name",actName);//活动名称
        requestData.put("send_name", "龙蛙");//商户名称
        requestData.put("amt_type", "ALL_RAND");//红包金额设置方式  ALL_RAND-随机
        requestData.put("remark", remark);//备注
        requestData.put("wishing", wishing);//红包祝福语
        requestData.put("total_num", "1");//红包发放总人数
        requestData.put("total_amount", amount);//付款金额
        requestData.put("client_ip", spbillCreateIp);//IP地址
        requestData.put("sign", Signature.getSign4MPString(requestData));
        return postByXMLForSSL("https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack", requestData, apiCertPath);
    }
    /**
     * 微信公众平台 微信客服接口
     * @throws Exception
     */
    public void wxkefu() throws Exception{

        Map<String, String> map = this.fetchAccessToken4ClientCredential();
        String accessToken = map.get("access_token");
        String strJson = "{\"touser\" :\"o7E6KuHcQAEpTe-ljP6IIhLK15Gg\",";
        strJson += "\"msgtype\":\"text\",";
        strJson += "\"text\":{";
        strJson += "\"content\":\"Hello World\"";
        strJson += "}}";
        String url = "https://api.weixin.qq.com/cgi-bin/message/custom/send?&body=0&access_token=" + accessToken;

        System.out.println(url);
        this.post(url, strJson);
    }

    public void buildWxHuiHua(Map getMap) throws Exception{
        Map<String, String> map = this.fetchAccessToken4ClientCredential();
        String accessToken = map.get("access_token");
        String strJson = "{\"touser\" :\""+ getMap.get("openId") +"\",";
        strJson += "\"msgtype\":\"text\",";
        strJson += "\"text\":{";
        strJson += "\"content\":\""+ getMap.get("content") +"\"";
        strJson += "}}";
        String url = "https://api.weixin.qq.com/cgi-bin/message/custom/send?&body=0&access_token=" + accessToken;
        System.out.println(url);
        this.sendPost(url, strJson);
    }

    /**
     * 解决中文乱码的post请求连接
     * @param url
     * @param json
     * @return
     */
    public String sendPost(String url, String json){
        PrintWriter out = null;
        BufferedReader in = null;
        String result = "";
        try {
            URL realUrl = new URL(url);
            // 打开和URL之间的连接
            URLConnection conn = realUrl.openConnection();
            //设置通用的请求属性
            conn.setRequestProperty("user-agent","Mozilla/5.0 (Windows NT 6.1; WOW64; rv:21.0) Gecko/20100101 Firefox/21.0)");
            // 发送POST请求必须设置如下两行
            conn.setDoOutput(true);
            conn.setDoInput(true);
            // 获取URLConnection对象对应的输出流
            OutputStreamWriter outWriter = new OutputStreamWriter(conn.getOutputStream(), "utf-8");
            out = new PrintWriter(outWriter);
            // 发送请求参数
            out.print(json);
            // flush输出流的缓冲
            out.flush();
            // 定义BufferedReader输入流来读取URL的响应
            in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
            String line;
            while ((line = in.readLine()) != null) {
                in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
                result += line;
            }
        } catch (Exception e) {
            System.out.println("发送 POST 请求出现异常！"+e);
            e.printStackTrace();
        }
        //使用finally块来关闭输出流、输入流
        finally{
            try{
                if(out!=null){
                    out.close();
                }
                if(in!=null){
                    in.close();
                }
            }
            catch(IOException ex){
                ex.printStackTrace();
            }
        }
        return result;
    }

    /**
     * 微信公众平台 微信聊天记录接口
     * @throws Exception
     */
    public void wxjilu() throws Exception{

        Map<String, String> map = this.fetchAccessToken4ClientCredential();
        String accessToken = map.get("access_token");
        String strJson = "{\"starttime\" :\"1503508280\",";
        strJson += "\"endtime\":\"1503570783\",";
        strJson += "\"msgid\":\"1\",";
        strJson += "\"number\":\"10000\",";
        String url = "https://api.weixin.qq.com/customservice/msgrecord/getmsglist?access_token=" + accessToken;
        System.out.println(url);
        this.post(url, strJson);
    }


    /**
     * 微信公众平台 http请求
     * @param url
     * @param json
     */
    public void post(String url, String json)
    {
        DefaultHttpClient client = new DefaultHttpClient();
        HttpPost post = new HttpPost(url);
        try
        {
            StringEntity s = new StringEntity(json);
            s.setContentEncoding("UTF-8");
            s.setContentType("application/json");
            post.setEntity(s);
            HttpResponse res = client.execute(post);
            if (res.getStatusLine().getStatusCode() == HttpStatus.SC_OK)
            {
                HttpEntity entity = res.getEntity();
                System.out.println(EntityUtils.toString(entity, "utf-8"));
            }
        }
        catch (Exception e)
        {
            throw new RuntimeException(e);
        }
    }
    /**
     * 查询微信企业付款
     * https://api.mch.weixin.qq.com/mmpaymkttransfers/gettransferinfo
     * @return
            {
                nonce_str=ict1kn6ar6c9df0x57sa,
                partner_trade_no=reward2,
                payment_time=2017-08-18 15:40:06,
                payment_no=1000018301201708189223134713,
                return_msg=,
                return_code=SUCCESS
            }
     * @throws IOException
     */
    public Map<String, Object> gettransferinfo(String partnerTradeNo,String apiPath) throws Exception{

        //请求路径
        Map<String, String> requestData = new HashMap();
        requestData.put("partner_trade_no", partnerTradeNo);
        requestData.put("appid", Configure.appID);
        requestData.put("mch_id", Configure.mchID);
        requestData.put("nonce_str",  RandomStringGenerator.getRandomStringByLength(20));
        requestData.put("sign", Signature.getSign4MPString(requestData));

        return postByXMLForSSL("https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/gettransferinfo", requestData, apiPath);
    }
    /**
     * 公众号创建和更新菜单
     * @return
     * @function 从远端获取到Access Token,注意,该AccessToken用于用户认证
     * @url https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN
     */
    public String createMenuForMP(String menuJson) throws Exception {
        return getAPIEnter4Menu("create", menuJson);
    }

    /**
     * 公众号删除菜单
     * @return
     * @function 从远端获取到Access Token,注意,该AccessToken用于用户认证
     * @url https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=ACCESS_TOKEN
     */
    public String deleteMenuForMP() throws Exception {
        return getAPIEnter("delete");
    }

    /**
     * 公众号查看菜单
     * @return
     * @function 从远端获取到Access Token,注意,该AccessToken用于用户认证
     * @url https://api.weixin.qq.com/cgi-bin/menu/get?access_token=ACCESS_TOKEN
     */
    public String getMenuForMP() throws Exception {
        return getAPIEnter("get");
    }

    private String getAPIEnter(String action) throws IOException, DocumentException {
        return getAPIEnter4Menu(action, null);
    }

    private String getAPIEnter4Menu(String action, String data) throws IOException, DocumentException {
        Map<String, String> map = this.fetchAccessToken4ClientCredential();
        System.out.println("map: " + map);
        String accessToken = map.get("access_token");
        StringBuilder sb = new StringBuilder();
        sb.append("https://");
        sb.append(API_WEIXIN_HOST)
                .append("/cgi-bin/menu/").append(action).append("?access_token=")
                .append(accessToken);

        if("create".equals(action)){
            return postByJSON(sb.toString(), data);
        }else{
            return getByJSON(sb.toString());
        }
    }

    /**
     * 公众号 发布模版消息
     * @return
     * @function 从远端获取到Access Token,注意,该AccessToken用于用户认证
     * @url https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=ACCESS_TOKEN
     */
    public String getAPIEnter4TemplateMsg(String data) throws Exception {

        Map<String, String> map = this.fetchAccessToken4ClientCredential();
        System.out.println("map: " + map);
        String accessToken = map.get("access_token");
        StringBuilder sb = new StringBuilder();
        sb.append("https://");
        sb.append(API_WEIXIN_HOST)
                .append("/cgi-bin/message/template/send").append("?access_token=")
                .append(accessToken);
        return postByJSON(sb.toString(), data);
    }

    public String sendAPIEnter4TemplateMsg(TemplateData data) throws Exception {
        return getAPIEnter4TemplateMsg(data.build());
    }

    /**
     * 公众号 一次性订阅消息 1
     * @return
     * @url https://mp.weixin.qq.com/mp/subscribemsg?action=get_confirm&appid=wxaba38c7f163da69b&scene=1000&template_id=1uDxHNXwYQfBmXOfPJcjAS3FynHArD8aWMEFN
            RGSbCc&redirect_url=http%3a%2f%2fsupport.qq.com&reserved=test#wechat_redirect
     */
    public String subscribemsg(String url) throws Exception {
        StringBuilder sb = new StringBuilder();
        sb.append("https://");
        sb.append("mp.weixin.qq.com/mp/subscribemsg?action=get_confirm&appid=").append(Configure.appID)
                .append("&scene=1&template_id=iH6w6BrcVTrkXZrQW80XSeKz8mpiRvmEkIkoBDNB1rQ")
                .append("&redirect_url=").append(URLEncoder.encode(url,"utf-8"))
                .append("&reserved=test#wechat_redirect");
        return sb.toString();
    }

    /**
     * 公众号 一次性订阅消息，重定向回复处理
     * @return
     * @function 从远端获取到Access Token,注意,该AccessToken用于用户认证
     * @url https://api.weixin.qq.com/cgi-bin/message/template/subscribe?access_token=ACCESS_TOKEN
     */
    public String getAPIEnter4subscribemsg(TemplateData data) throws Exception {

        Map<String, String> map = this.fetchAccessToken4ClientCredential();
        System.out.println("map: " + map);
        String accessToken = map.get("access_token");
        StringBuilder sb = new StringBuilder();
        sb.append("https://");
        sb.append(API_WEIXIN_HOST)
                .append("/cgi-bin/message/template/subscribe").append("?access_token=")
                .append(accessToken);
        return postByJSON(sb.toString(), data.build());
    }

}
